package com.xff.util;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

@Aspect
@Component
@Order(value = 200)
public class LogUtil {

    /*
    *
    * AOP ：日志、安全、权限、事务
    *
    * 通知注解有以下几种类型：
    * @Before 前置通知   方法执行之前完成
    * @AfterReturning  返回通知   在返回结果之后运行
    * @AfterThrowing  异常通知   在出现异常的时候使用
    * @After  后置通知  在方法执行完成之后执行
    * @Around  环绕通知
    *
    *
    * 可以使用通配符的方式*
    *    1、*可以用来一个或者多个字符
    *    2、匹配任意的参数
    *    3、只能匹配单层
    *    4、修饰符不知道的时候可以省略不写，不可以用*来代替
    *    5、返回值可以使用*
    *
    *  “..”：
    *      1、可以匹配多个参数，任意类型
    *      2、可以匹配多层路径
    *
    *    最简洁的方式（第一个*表示代替返回值）：
    *      execution(* *(..))
    *      execution(* com..*(..))
    *     如果表达式用*开头则可以代替所有
    *
    *    在使用表达式时还支持逻辑运算
    *    &&：
    *    同时满足多个
    *    execution(public void com.xff.controller.PersonController.save(..)) && execution(* *(..))
    *    ||：
    *     多个条件满足一个即可
    *     execution(public void com.xff.controller.PersonController.save(..)) || execution(* *(..))
    *    ！：
    *    取反
    *    ！execution(public void com.xff.controller.PersonController.save(..))
    *
    *
    *     当应用程序中包含多个切面类的时候，具体的执行顺序是什么样？
     *          按照切面类的名称的首字母进行排序操作，按照字典序
     *          如果需要认为的规定顺序，可以在切面类上添加@Order注解同时可以添加具体的值
     *          值越小，越优先
    *
    * */

    @Pointcut("execution(public * com.xff.controller.PersonController.save(..))")
    public void myPointCut(){}

    @Pointcut("execution(* *(..))")
    public void mypointCut1(){}

    @Before(value = "myPointCut()")
    private static void start(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        Object[] args = joinPoint.getArgs();
        System.out.println("Log----"+signature.getName()+"方法开始执行: 参数是"+Arrays.asList(args));
//        System.out.println("signature.getDeclaringType()="+signature.getDeclaringType());
//        System.out.println("signature.getDeclaringTypeName()="+signature.getDeclaringTypeName());
//        System.out.println("signature.getModifiers()="+signature.getModifiers());
    }

    @AfterReturning(value = "myPointCut()",returning = "result")
    public static void stop(JoinPoint joinPoint,Object result){
        Signature signature = joinPoint.getSignature();
        System.out.println("Log----"+signature.getName()+"方法执行结束: 结果是"+result);
    }

    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public static void logException(JoinPoint joinPoint,Exception e){
        Signature signature = joinPoint.getSignature();
        System.out.println("Log----"+signature.getName()+"方法抛出异常："+e.getMessage());
    }

    @After("myPointCut()")
    public static void logFinally(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        System.out.println("Log----"+signature.getName()+"方法执行结束....over");
    }
    @Around("myPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        Signature signature = point.getSignature();
        signature.getDeclaringType();
        Object[] args = point.getArgs();
        System.out.println("Log----"+"环绕通知："+signature.getName()+"方法开始执行，参数是："+Arrays.asList(args));
        Object result=null;
        try {
             point.proceed(args);
             result=100.2;
            System.out.println("Log----"+"环绕通知："+signature.getName()+"方法返回结果："+result);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("Log----"+"环绕通知："+signature.getName()+"抛出异常");
            throw throwable;

        }finally {
            System.out.println("Log----"+"环绕通知："+signature.getName()+"执行结束....over");
        }
        return result;
    }
}
